Web之困笔记
点击蓝字
学习干货
前段时间orange的BH2017议题中提到的不同语言和库的url解析对SSRF的影响,让我想起了web之困中曾经讨论过浏览器对url的解析过程也同样是一团乱麻,之前只是快速过了一遍这本书,最近有时间了再重新看一遍。
ff = firefox; ch = chrome; sf = safari
一切从url开始
URL结构:
scheme://login:password@address:ort/path/to/resource?querystring#fragment
协议(scheme)
以 : 结尾,规定在 : 之前,只能出现 + - .三个符号,但在实际环境里所有的浏览器都会忽略换行符和空格,IE还会允许所有的不可打印字符,chrome会忽略0x00和NUL。
层级url
含有 // 的url
问题:如果碰到一个非层级的url含有//如何处理?反之亦然
导致各家浏览器的解析不同:
1. http:example.com 在ff,ch,sf里会等同于http://*
2. javascript://example.com/%0Aalert(1) 所有常用浏览器会认为是非层级的javascript伪协议
身份验证
不提供则默认匿名,大多数浏览器对身份验证部分接受所有字符,而sf拒接< > { },ff拒绝换行符
服务器地址
必须提供:不区分大小写的域名、ipv4地址或在[]中的ipv6地址,ff还接受在[]中的IPv4和主机。ip地址可以使用八进制、十进制、十六进制,甚至可以吧其中几个或全部8位元数据拼在一起再转成单个整数的写法:127.0.0.1 -> 0x7f.1
层级的文件路径
/aaa/bbb/ccc.txt 这个格式是直接从UNIX目录语义借用过来的,所以也支持在路径中出现/../和/./
如何解析一个url
1. 提取协议名称:扫描第一个:字符,左边部分为协议名称
2. 去除层级url标记//
3. 获取授权部分信息:扫描/ ? #,首先定位登录信息(@),接着提取目标地址,大多数浏览器接受\作为分隔符的方法
4. 确定路径
5. 提取查询字符串
6. 提取片段id
实际上url的解析非常困难和混乱:
一个例子:http://example.com&xxx=123@167772161/这个url的目标地址实际是10.0.0.1(167772161转化为十六进制为A000001,即10.0.0.1)
又一个例子:http://a.com\@b.cx在ff里,会带往b.cx,而在其他浏览器,\会被认为是分隔符,会带往a.com
IE里一个更抓狂的例子:http://a.com/;.b.cx ie允许;出现在主机名称,其他浏览器会补全为/a.com/;.b.cx
保留字符和百分号编码
url解析的大前提:: / ? # [] @ ! $ & ‘ () * + , ; = 不出现在url里,否则会破坏解析。但是有时需要使用它们,就需要进行url编码,这个编码由浏览器完成,但是还是会出现分歧:
例如http://a@b@c 应该对哪个@进行url编码?ie和sf认为编码后一个,其他的编码前一个。
注意:禁止保留字符以非编码形式出现,但是不禁止非保留字符以url编码形式出现,所有浏览器都不会编码片段id
对非us-ascii文本字符的处理
IDNA标准,2002年被发现漏洞,前段时间无法分辨的钓鱼网站域名也是类似的方法?
常见的url协议及功能
浏览器本身支持的协议
由浏览器内部直接处理 http: https: ftp: file: ff仍然支持gopher: ie仍然支持shttp:
第三方应用和插件支持的协议
根据协议交给外部的应用程序 mialto: news: firefoxurl: (在浏览器里启动ff程序)cf: (在ie里调用chrome) 第三方协议的处理程序往往漏洞百出,尽量少用
未封装的伪协议
javascript: data:
封装过的伪协议
view-source: jar:
相对url的解析
如果url不是由有效协议开始,并且没有冒号或者//,那就是需要被引用的相对url,如果解析这个url的时候没有上下文,就拒绝访问。
相对url的类型:
1. 有协议名称,没有授权信息(http:foo.txt),以url自身为准,出了授权信息以引用页面为准。
2. //a.com: 保持当前页面的协议不变
3. ../1.txt: 拼接在url最右边的/后面
4. ?a=b: 原封不动的加上查询字符串和片段id
5.#url: 同上,不会导致页面重新加载
HTTP协议
HTTP/1.1 要求客户端不仅要接受CRLF和LF两种换行符,还要接受CR字符
对重复头域的解析
没有规定接收第一个或第二个,一半的浏览器接收第一个,而另一半接收第二个,而现在服务端,apche接收第一个host头,IIS不接收多个HOST头的情况
也没有规定两个版本不同(HTTP/1.0 HTTP/1.1)但是一样功能的头域同时出现会怎么样
HTML语言
传统HTML解析不严格,相反XML解析非常严格:所有标签必须严格匹配,命名大小写要一致,要显示明确的闭合
HTML解析器
用XHTML解析器,对格式错误的容忍度极低,而用传统HTML解析器,则会出现许多含混的解析 <img src="xx" title="hello" class=example>
img和src中的空格可以用不太常见的垂直制表符(0x0b)和进纸换页符(0x0c)替代,ff里可以用正斜杠代替,opera里可以用0xa0代替。
ie可以用`代替引号和双引号
ie会识别<img src=1.jpg?value=">123!">中的value为”>123!”
多重标签的交互
<i <b>
大多数浏览器会解析为<i>,但在ff4.0之前会解析为<i><b>
层叠样式表
在HTML里嵌入样式表时,会优先执行对HTML的解析,且HTML的解析是独立于CSS语法规则之外的,所以在CSS中如果包含HTML语法会非常不安全。
CSS的解析在遇到语法错误的时候仍会继续工作
CSS用\后面跟1-6位的十六进制数字来转义,例如e可以编码为\65 \065 \000065,但如果e后面一个字符是有效的十六进制数字的时候会出错,例如ea被编码为\65a,则会按照\65a整个来解析,成为unicode里一个阿拉伯符号。CSS针对这个问题有笨拙的解决方案:转以后加一个空格作为终止符。
浏览器端脚本
JS的解析和执行阶段被严格分开,所以允许在一个script标签内先调用函数再定义函数(只对函数有效而对变量无效)。
执行顺序和错误处理:同一个标签内解析正确后按顺序执行,如执行遇到错误不执行错误后面的语句,标签之间的错误互不干扰。
JS脚本字符编码
对某些控制字符,可以用c风格的方法:\b \t \v \r \n
3位数字按8位原字节八进制字符编码的方式,无前缀(\145代表e)
2位数字,按8位原字节16禁止字符编码,前缀位x(\x65代表e)
4位数字,按16位原字节的16禁止Unicode数值编码,前缀为u(\u0065代表e)
反斜杠后面跟非8进制数字,也不是1中的转义字符,按反斜杠后面的字符的字面意义直接处理
浏览器安全部分-内容隔离
DOM的同源策略
协议-域名-端口
document.domain和postMessage()
同源策略与浏览器身份验证信息缺少同步机制 -> csrf等漏洞的产生
XMLHttpRequest的同源策略
CORS:返回的数据包里包含特定响应头的时候,浏览器才能读取响应数据
源的继承
about:blank data: 和 javascript:
同源策略之外的世界
点击劫持
X-Fram-Options: sameorigin
其他的安全边界
直接跳转到 file: 会造成的安全影响 DNS rebinding -> DNS pinning
内容识别机制
本文作者:Styxz
别忘了投稿哟!!!
合天公众号开启原创投稿啦!!!
大家有好的技术原创文章。
欢迎投稿至邮箱:edu@heetian.com;
合天会根据文章的时效、新颖、文笔、实用等多方面评判给予100元-500元不等的稿费哟。
有才能的你快来投稿吧!
合天网安实验室
网址 : www.hetianlab.com
电话:4006-123-731
长按图片,据说只有颜值高的人才能识别哦→